/**
 * @Author: Gosin
 * @Date: 2020/3/17 15:26
 */
package main

import (
	"bytes"
	"encoding/json"
	"git.900sui.cn/kc/kcgin"
	"git.900sui.cn/kc/kcgin/logs"
	"git.900sui.cn/kc/kcgin/utils"
	"git.900sui.cn/kc/rabbitmq"
	"github.com/streadway/amqp"
	"io/ioutil"
	"net"
	"net/http"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

var client *http.Client

func main() {
	client = &http.Client{Transport: &http.Transport{Dial: func(proto, addr string) (conn net.Conn, err error) { return net.Dial("unix", "/var/run/docker.sock") }}}

	basepath := kcgin.AppConfig.String("githook.base.repos")
	err := rabbitmq.Rabbitmq.Consume(kcgin.AppConfig.String("queue.githook"), func(msg amqp.Delivery) {
		repos := string(msg.Body)
		reposArr := strings.Split(repos, "||")
		repos = reposArr[0]
		devVersion := "master"
		if len(reposArr) > 1 && len(reposArr[1]) > 0{
			devVersion = reposArr[1] //比如：dev1.1
		}
		reposPath := ""
		dockerName := ""
		if devVersion == "master"{
			if strings.HasPrefix(repos, "api") {
				reposPath = filepath.Join(basepath, "api", strings.ToLower(repos[3:]))
				dockerName = "api_api_" + strings.ToLower(repos[3:])
			} else if strings.HasPrefix(repos, "rpc") {
				reposPath = filepath.Join(basepath, "rpc", strings.ToLower(repos[3:]))
				dockerName = "rpc_rpc_" + strings.ToLower(repos[3:])
			} else if repos == "consumeTask" {
				reposPath = filepath.Join(basepath, "other", repos)
				dockerName = "task_"
			} else if strings.HasPrefix(repos, "h5") {
				reposPath = filepath.Join(basepath, "h5project", repos)
				dockerName = ""
			} else {
				reposPath = filepath.Join(basepath, "other", repos)
				dockerName = "other_" + repos
			}
		}else{
			devVersionStr := strings.Replace(devVersion, ".", "", -1)
			logs.Info("devVersionStr: ", devVersionStr)
			if strings.HasPrefix(repos, "api") {
				reposPath = filepath.Join(basepath, "api_"+devVersion, strings.ToLower(repos[3:]))
				dockerName = "api_api_" + strings.ToLower(repos[3:])+"_"+devVersionStr
			} else if strings.HasPrefix(repos, "rpc") {
				reposPath = filepath.Join(basepath, "rpc_"+devVersion, strings.ToLower(repos[3:]))
				dockerName = "rpc_rpc_" + strings.ToLower(repos[3:])+"_"+devVersionStr
			} else if repos == "consumeTask" {
				reposPath = filepath.Join(basepath, "other_"+devVersion, repos)
			}
		}

		if utils.FileExists(reposPath) {
			if !strings.HasPrefix(repos, "h5") {
				cmd := exec.Command("git", "-C", reposPath, "checkout", "--", "go.mod", "go.sum")
				res, err := cmd.Output()
				if err != nil {
					logs.Info(err, ",errcommand:", "git", "-C", reposPath, "checkout", "--", "go.mod", "go.sum")
					return
				}
				logs.Info(string(res))
			}
			var stderr bytes.Buffer
			cmd := exec.Command("git", "-C", reposPath, "pull", "--progress", "-v", "--no-rebase", "origin")
			res, err := cmd.Output()
			if err != nil {
				logs.Info(err, stderr.String(), ",errcommand:", "git", "-C", reposPath, "pull", "--progress", "-v", "--no-rebase", "origin")
				return
			}
			logs.Info(string(res))
			if strings.Index(string(res), "Fast-forward") != -1 || strings.Index(string(res), "Merge made") != -1 {
				cmd = exec.Command("git", "-C", reposPath, "submodule", "update")
				res, err = cmd.Output()
				if err != nil {
					logs.Info(err, ",errcommand:", "git", "-C", reposPath, "submodule", "update")
					return
				}
				logs.Info(string(res))
				if dockerName != "" {
					updateService(dockerName)
				}

				//if repos == "consumeTask" {
				//	for serverName := range getServiceNames(string(res)) {
				//		updateService(dockerName + serverName)
				//	}
				//} else {
				//	if dockerName != "" {
				//		updateService(dockerName)
				//	}
				//}
			}
		} else {
			logs.Info("can not find any repo", repos)
		}
	})
	if err != nil {
		logs.Info(err)
	}
}
func updateService(serviceName string) {
	baseUrl := "http://localhost/services/" + serviceName
	resp, err := client.Get(baseUrl)
	if err != nil {
		logs.Info(err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logs.Info(err)
		return
	}
	data := map[string]interface{}{}
	if err := json.Unmarshal(body, &data); err != nil {
		logs.Info(err)
		return
	}

	if _, ok := data["Version"].(map[string]interface{}); !ok {
		logs.Info("filed service " + serviceName)
		return
	}

	version := int(data["Version"].(map[string]interface{})["Index"].(float64))
	data["Spec"].(map[string]interface{})["TaskTemplate"].(map[string]interface{})["ForceUpdate"] = int(data["Spec"].(map[string]interface{})["TaskTemplate"].(map[string]interface{})["ForceUpdate"].(float64)) + 1
	marshal, _ := json.Marshal(data["Spec"])

	resp, err = client.Post(baseUrl+"/update?version="+strconv.Itoa(version), "application/json", strings.NewReader(string(marshal)))
	if err != nil {
		logs.Info(err)
		return
	}
	defer resp.Body.Close()
	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		logs.Info(body)
		return
	}
	logs.Info(serviceName, "reload success")
}

func getServiceNames(gitRes string) map[string]int {
	res := map[string]int{}
	for _, val := range regexp.MustCompile(` (\S+)\.go `).FindAllStringSubmatch(gitRes, -1) {
		res[strings.ReplaceAll(val[1], "/", "_")] = 0
	}
	return res
}
